<?php

namespace App\Service\delivery;
use App\Job\WxRefundOrderJob;
use App\Job\DyRefundOrderJob;
use App\Model\Applet;
use App\Model\AppletCompany;
use App\Model\DataPaymentCheckLog;
use App\Model\DataPaymentRefund;
use App\Model\DataPaymentRefundLog;
use App\Model\Payment;
use App\Service\CommicService;
use App\Model\Company;
use GuzzleHttp\Client;
use Hyperf\Utils\ApplicationContext;
use App\Common\Response\SystemCode;
use Hyperf\DbConnection\Db;
use Hyperf\AsyncQueue\Driver\DriverFactory;
use Hyperf\AsyncQueue\Driver\DriverInterface;

class OrderService extends CommicService
{

    public static $getTokenUrl = "https://api.weixin.qq.com/cgi-bin/token";

    public static $wxpayUrl = "https://api.mch.weixin.qq.com";

    protected $mchid = '1658026575';//商户号
    protected $serialNo = '504D25AC484AD63DA05EBE9A48F656E3644DE8EA';//商户序列号

    protected $privateKeyPath = '/home/wwwroot/ml_api/wx/10000/apiclient_key.pem';//证书物理路径（私钥）


    public static $wxStatus = [
        0 =>'订单初始化（未创建成功，不可用于支付）',
        1 =>'订单创建成功',
        2 => '订单已经支付，待发货',
        3 => '订单发货中',
        4 => '订单已发货',
        5 => '订单已经退款',
        6 => '订单已经关闭（不可再使用）',
        7 => '订单退款失败',
        8 => '用户退款完成',
        9 => '回收广告金完成',
        10 => '分账回退完成'
    ];
    public static $wxsettState = [
        0 =>'未开始结算',
        1 =>'结算中',
        2 => '结算成功'
    ];

    public function __construct(DriverFactory $driverFactory)
    {
        $container = ApplicationContext::getContainer();
        $this->redisService = $container->get(\Hyperf\Redis\Redis::class);
        $this->httpclient = new Client();
        $this->driver = $driverFactory->get('default');
    }
    /**
     * 获取订单详情
     */
    public function getOrderDetail(Object $paymentInfo){

        //查询小程序的key
        $appletInfo = Applet::query()->where('id', $paymentInfo->applet_id)->select(['id', 'AppKey', 'app_id', 'app_secret','SALT'])->first();

        //微信的订单而且是虚拟支付
        if($paymentInfo->type == 1 && $paymentInfo->pay_type == 1) {
            //2023-12-28区分本地和线上
            if (!empty(env('REDIS_HOST')) && env('REDIS_HOST') == '10.10.10.10') {
                $accessToken = env('WX_TEST_TOKEN');
            } else {
                $accessToken = $this->getWxAccessToken($appletInfo->id, $appletInfo->app_id, $appletInfo->app_secret);
            }
            if (!empty($accessToken)) {

                $userInfo = Db::table('data_user_' . $paymentInfo->applet_id)->where('id', $paymentInfo->user_id)->first();
                $clickUserInfo = $this->getUserAppletInfo(2);
                $orderResult = $this->checkWxOrder($clickUserInfo['id'], $paymentInfo->id, $userInfo->xc_open_id,
                    $paymentInfo->order_id, $appletInfo->AppKey, $accessToken, 1);

                if ($orderResult['errcode'] == 0) {
                    $orderInfo = $orderResult['order'];
                    $returnData = [
                        'order_id' => $orderInfo['order_id'],                                           //订单号
                        'create_time' => date('Y-m-d H:i:s', $orderInfo['create_time']),          //创建时间
                        'update_time' => date('Y-m-d H:i:s', $orderInfo['update_time']),         //更新时间
                        'status' => $orderInfo['status'],                                              //状态
                        'status_name' => self::$wxStatus[$orderInfo['status']],
                        'order_fee' => $orderInfo['order_fee'] / 100,                                     //订单金额，单位分
                        'paid_fee' => $orderInfo['paid_fee'] / 100,                                       //用户支付金额
                        'paid_time' => !empty($orderInfo['paid_time']) ? date('Y-m-d H:i:s', $orderInfo['paid_time']) : '',               //支付时间
                        'provide_time' => !empty($orderInfo['provide_time']) ? date('Y-m-d H:i:s', $orderInfo['provide_time']) : '',      //发货时间
                        'wxpay_order_id' => !empty($orderInfo['wxpay_order_id']) ? $orderInfo['wxpay_order_id'] : '',                              //微信支付交易单号
//                        'sett_time' =>  date('Y-m-d H:i:s',$orderInfo['sett_time']),            //结算时间
//                        'sett_state' => self::$wxsettState[$orderInfo['sett_state']],
                        'is_apply' => 0,
                    ];
                    //判断订单是否已经申请退款
                    $refundInfo = DataPaymentRefund::query()->where(['payment_id' => $paymentInfo->id])->first();
                    if (!empty($refundInfo)) {
                        $returnData['is_apply'] = 1;
                    }
                    return $this->response(SystemCode::SYSTEM_SUCCESS, '查询成功', $returnData);
                } else {
                    $errorMeg = $orderResult['errmsg'];
                    return $this->response(SystemCode::SYSTEM_ERROR, $errorMeg);
                }
            }
        //20240502 新增抖音查询订单
        }elseif($paymentInfo->type == 2 && in_array($paymentInfo->pay_type,[3,4,5])){

            //2024-05-02区分本地和线上
            if (!empty(env('REDIS_HOST')) && env('REDIS_HOST') == '10.10.10.10') {
                $accessToken = env('DY_TEST_TOKEN');
            } else {
                $accessToken = $this->getDyAccessToken($appletInfo->id);
            }

            if (!empty($accessToken)) {
                $clickUserInfo = $this->getUserAppletInfo(2);
                $orderResult = $this->checkDyOrder($clickUserInfo['id'], $paymentInfo->id,$paymentInfo->order_id,$accessToken);
                if ($orderResult['err_no'] == 0) {
                    $orderInfo = $orderResult['data'];
                    $returnData = [
                        'dypay_order_id' => $orderInfo['order_id'],                                           //订单号
                        'order_id' => $orderInfo['out_order_no'],                                           //订单号
                        'status' => $orderInfo['pay_status'] == 'SUCCESS' ? 4 : 0,                                              //状态
                        'status_name' => $orderInfo['pay_status'],
                        'order_fee' => $orderInfo['total_amount'] / 100,                                     //订单金额，单位分
                        'paid_fee' => $orderInfo['total_amount'] / 100,                                       //用户支付金额
                        'create_time' => !empty($orderInfo['trade_time']) ? date('Y-m-d H:i:s', $orderInfo['trade_time']/1000) : '',        //交易下单时间
                        'paid_time' => !empty($orderInfo['pay_time']) ? date('Y-m-d H:i:s', $orderInfo['pay_time']/1000) : '',               //支付时间
                        'channel_pay_id' => !empty($orderInfo['channel_pay_id']) ? $orderInfo['channel_pay_id'] : '',                              //渠道支付单号
                        'is_apply' => 0,
                    ];
                    //判断订单是否已经申请退款
                    $refundInfo = DataPaymentRefund::query()->where(['payment_id' => $paymentInfo->id])->first();
                    if (!empty($refundInfo)) {
                        $returnData['is_apply'] = 1;
                    }
                    return $this->response(SystemCode::SYSTEM_SUCCESS, '查询成功', $returnData);
                } else {
                    $errorMeg = $orderResult['errmsg'];
                    return $this->response(SystemCode::SYSTEM_ERROR, $errorMeg);
                }
            }
        }
        return $this->response(SystemCode::SYSTEM_ERROR, '请求失败');
    }
    /**
     * 申请退款订单
     */
    public function refundOrder(Array $params){

        $payment_id             = $params['payment_id'];
        $refund_reason          = $params['refund_reason'];
        $paymentInfo = Payment::query()->select(['id','type','status','applet_id','user_id','order_id','goods_id','pay_type','amount'])->where(['id' => $payment_id,'status' => 2])->first();
        if(empty($paymentInfo)){
            return $this->response(SystemCode::SYSTEM_ERROR, '订单不存在或者订单状态不正确');
        }
        $key = 'refund_apply_order';
        //判断用户一分钟点击多少次
        $clickNum = $this->redisService->get($key);
        if(empty($clickNum)){
            $this->redisService->setex($key,60,0);
            $clickNum = 1;
        }
        if($clickNum > 5){
            return $this->response(SystemCode::SYSTEM_ERROR, '点击次数太频繁，请稍后再点击');
        }else{
            $this->redisService->incr($key);
        }
        //判断订单是否已经申请退款
        $refundInfo = DataPaymentRefund::query()->where(['payment_id' => $paymentInfo->id])->first();
        if(!empty($refundInfo)){
            return $this->response(SystemCode::SYSTEM_ERROR, '订单已申请退款，请勿再此点击');
        }
        //微信的订单只有微信虚拟支付,抖音支付
        if(($paymentInfo->type == 1 && $paymentInfo->pay_type == 1) || $paymentInfo->type == 2){
            $clickUserInfo = $this->getUserAppletInfo(2);
            $this->installRefundData($clickUserInfo['id'],$paymentInfo,$refund_reason);
           return $this->response(SystemCode::SYSTEM_SUCCESS, '申请退款成功');
        }
        return $this->response(SystemCode::SYSTEM_ERROR, '请求失败');
    }
    /**
     * 调用微信退款
     */
    public function refundWxOrder(DataPaymentRefund $refundInfo){
        $payment_id             = $refundInfo->payment_id;
        $refund_reason          = $refundInfo->refund_reason;

        $paymentInfo = Payment::query()->select(['id','type','status','applet_id','user_id','order_id','goods_id','pay_type','amount'])->where(['id' => $payment_id,'status' => 2])->first();
        if(empty($paymentInfo)){
            return $this->response(SystemCode::SYSTEM_ERROR, '订单不存在或者订单状态不正确');
        }
        $key = 'refund_order';
        //判断用户一分钟点击多少次
        $clickNum = $this->redisService->get($key);
        if(empty($clickNum)){
            $this->redisService->setex($key,60,1);
            $clickNum = 1;
        }
        if($clickNum > 5){
            return $this->response(SystemCode::SYSTEM_ERROR, '点击次数太频繁，请稍后再点击');
        }else{
            $this->redisService->incr($key);
        }
        //微信的订单只有微信虚拟支付
        if($paymentInfo->type == 1 && $paymentInfo->pay_type == 1){
            $clickUserInfo = $this->getUserAppletInfo(2);
            $this->driver->push(new WxRefundOrderJob($refundInfo->id,$paymentInfo,$clickUserInfo['id'],$refund_reason));
            return $this->response(SystemCode::SYSTEM_SUCCESS, '申请退款成功');
        }
        return $this->response(SystemCode::SYSTEM_ERROR, '请求失败');
    }
    /**
     * 调用抖音退款
     * 20240502
     * bobo
     */
    public function refundDyOrder(object $refundInfo){
        $payment_id             = $refundInfo->payment_id;
        $paymentInfo = Payment::query()->select(['id','type','status','applet_id','user_id','order_id','goods_id','pay_type','amount'])->where(['id' => $payment_id,'status' => 2])->first();
        if(empty($paymentInfo)){
            return $this->response(SystemCode::SYSTEM_ERROR, '订单不存在或者订单状态不正确');
        }
        $key = 'refund_order';
        //判断用户一分钟点击多少次
        $clickNum = $this->redisService->get($key);
        if(empty($clickNum)){
            $this->redisService->setex($key,60,1);
            $clickNum = 1;
        }
        if($clickNum > 5){
            return $this->response(SystemCode::SYSTEM_ERROR, '点击次数太频繁，请稍后再点击');
        }else{
            $this->redisService->incr($key);
        }
        //抖音的订单只有微信虚拟支付
        if($paymentInfo->type == 2){
            $clickUserInfo = $this->getUserAppletInfo(2);
            $this->driver->push(new DyRefundOrderJob($refundInfo->id,$paymentInfo,$clickUserInfo['id'],$refundInfo->refund_reason));
            return $this->response(SystemCode::SYSTEM_SUCCESS, '申请退款成功');
        }
        return $this->response(SystemCode::SYSTEM_ERROR, '请求失败');
    }

    public function installRefundData($user_id,$paymentInfo,$refund_reason,$req_from=1,$status=1){

        $payment_id = $paymentInfo->id;
        $payment_user_id = $paymentInfo->user_id;
        $payment_applet_id = $paymentInfo->applet_id;
        $order_id = $paymentInfo->order_id;
        $type = $paymentInfo->type;
        $amount = $paymentInfo->amount;

        DataPaymentRefund::Create([
            'user_id' => $user_id,
            'payment_id' => $payment_id,
            'payment_user_id' => $payment_user_id,
            'payment_applet_id' => $payment_applet_id,
            'order_id' => $order_id,
            'type' => $type,
            'amount' => $amount,
            'status' => $status,
            'refund_reason' => $refund_reason,
            'req_from' => $req_from,
        ]);
    }

    /**
     * 检查微信订单
     */
    public function checkWxOrder($click_user_id,$payment_id,$xc_open_id,$order_id,$appkey,$accessToken,$type,$pay_type=1){

        if($pay_type == 1){

            $url = '/xpay/query_order';
            $params = [
                'openid' => $xc_open_id,
                'env'=>0,
                'order_id' => $order_id
            ];
            $pay_sig = $this->get_paySig($appkey,$url,$params);
            $orderUrl = 'https://api.weixin.qq.com'.$url.'?access_token='.$accessToken.'&pay_sig='.$pay_sig;
            $orderResult  = $this->request($params,$orderUrl, 'POST');
            if($orderResult['errcode'] == 0){
                $return_msg = '获取成功';
            }else{
                $return_msg = $orderResult['errmsg'];
            }
            //插入日志
            $this->installCreateLog($click_user_id,$payment_id,$return_msg,$orderResult,$orderUrl,$params,$type);
            return $orderResult;
        }else{
            $orderUrl = self::$wxpayUrl.'/v3/pay/transactions/out-trade-no/'.$order_id;
            $params = [
                'mchid' => $this->mchid
            ];
            $orderResult  = $this->request($params,$orderUrl, 'GET');
            if($orderResult['errcode'] == 0){
                $return_msg = '获取成功';
            }else{
                $return_msg = $orderResult['errmsg'];
            }
            $this->installCreateLog($click_user_id,$payment_id,$return_msg,$orderResult,$orderUrl,$params,$type);
            return $orderResult;
        }

    }

    /**
     * 检查抖音订单
     */
    public function checkDyOrder($click_user_id,$payment_id,$order_id,$accessToken){

        $params = [
            'out_order_no'=>$order_id,
        ];
        $url = 'https://open.douyin.com/api/trade_basic/v1/developer/order_query';
        $orderResult  = $this->dyrequest($params,$url, 'POST',$accessToken);
        if($orderResult['err_no'] == 0){
            $return_msg = '获取成功';
        }else{
            $return_msg = $orderResult['err_msg'];
        }
        //插入日志
        $this->installCreateLog($click_user_id,$payment_id,$return_msg,$orderResult,$url,$params,1);
        return $orderResult;

    }

    public function getDypaySig($params, $SALT)
    {
        $rList = array();
        foreach ($params as $k => $v) {
            if ($k == "other_settle_params" || $k == "app_id" || $k == "sign" || $k == "thirdparty_id")
                continue;
            $value = trim(strval($v));
            $len = strlen($value);
            if ($len > 1 && substr($value, 0, 1) == "\"" && substr($value, $len, $len - 1) == "\"")
                $value = substr($value, 1, $len - 1);
            $value = trim($value);
            if ($value == "" || $value == "null")
                continue;
            array_push($rList, $value);
        }
        array_push($rList, "$SALT");
        sort($rList, 2);
        return md5(implode('&', $rList));
    }
    /**
     * 插入查看日志
     */
    public function installCreateLog($user_id,$payment_id,$return_msg,$reutrnData,$request_url,$request_params,$type){

        $return_text = json_encode($reutrnData);
        $request_params = json_encode($request_params);
        DataPaymentCheckLog::Create([
            'user_id' => $user_id,
            'payment_id' => $payment_id,
            'return_msg' => $return_msg,
            'return_text' => $return_text,
            'request_url' => $request_url,
            'request_params' => $request_params,
            'type' => $type,
        ]);
    }
    /**
     * 获取微信虚拟支付token
     */
    public function getWxAccessToken($applet_id,$app_id,$app_secret){

        $container = ApplicationContext::getContainer();

        $redis = $container->get(\Hyperf\Redis\RedisFactory::class)->get('wx');

        $key = 'wx_access_token';
        $key .= $applet_id;
        $accessToken = $redis->get($key);
        if(empty($accessToken)){
            $params         = [
                'grant_type' => 'client_credential',
                'appid'    => $app_id,
                'secret'   => $app_secret
            ];
            //获取token
            $accessTokenInfo     = $this->request($params, self::$getTokenUrl,'GET');

            if (!empty($accessTokenInfo['access_token'])){
                $accessToken = $accessTokenInfo['access_token'];
                $redis->setex($key,7100,$accessToken);
            }else{
                $accessToken = "";
            }
        }
        return $accessToken;
    }
    /**
     * 生成虚拟支付的pay_sig
     */
    public function get_paySig($appkey,$url,$signData) {
        $paySig = $this->calcPaySig($url, $signData, $appkey);
        return $paySig;
    }
    /**
     * 生成虚拟支付的pay_sig
     */
    private function calcPaySig($uri, $postBody, $appkey)
    {
        $needSignMsg = $uri . '&' . json_encode($postBody);
        $paySig = hash_hmac('sha256', $needSignMsg, $appkey);
        return $paySig;
    }

    function request(array $params, string $url,string $method,string $access_token = null)
    {
        try {

            $client   = new Client([
                'timeout' => 3
            ]);
            $headers       = ['Content-Type' => 'application/json'];
            if(!empty($access_token)){
                $headers['access-token'] = $access_token;
            }

            $requestParams = [
                'headers' => $headers,
            ];
            if ($method == 'GET') {
                $requestParams['query'] = $params;
            } else {
                $requestParams['json'] = $params;//json_encode($params,JSON_UNESCAPED_UNICODE);
            }
            $response = $client->request($method,$url, $requestParams);
            if ($response->getStatusCode() !== 200) {
                return '';
            }
            $result   = $response->getBody()->getContents();

            $resultArr = json_decode($result,true);
            return $resultArr;

        }catch (\Exception $e){

            $resultArr['errcode'] = '500';
            $resultArr['errmsg'] = $e->getMessage();
            return $resultArr;
        }

    }

}